package cn.ltpcloud.common.aspect;


import cn.ltpcloud.common.annotation.Log;
import cn.ltpcloud.common.entity.AjaxResult;
import cn.ltpcloud.common.pojo.mapper.SysLogMapper;
import cn.ltpcloud.common.pojo.po.SysLog;
import cn.ltpcloud.common.utils.ReqUtils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;

import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Date;

/**
 * @author jiejiebiezheyang
 * @since 2024-03-11 14:00
 */
@Aspect
@Component
@Order(2)
public class LogAspect {


    @Resource
    private SysLogMapper sysLogMapper;

    @Pointcut("@annotation(cn.ltpcloud.common.annotation.Log)")
    public void logPointCut() {
    }

    @Around("logPointCut()")
    private AjaxResult testAop(ProceedingJoinPoint point) throws Throwable {
        // 获取当前请求
        HttpServletRequest request = ReqUtils.getRequest();
        // 获取参数
        Object[] args = point.getArgs();
        // 获取目标方法
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Log log = method.getAnnotation(Log.class);

        long startTime = System.currentTimeMillis();
        AjaxResult result = null;
        try {
            result = (AjaxResult) point.proceed();// 执行目标方法 获取返回值
            long cost = System.currentTimeMillis() - startTime;
            // 保存
            log(log, request, result, signature, method, args, cost);
            return result;
        } catch (Exception e) {
            // 保存
            log(log, request, AjaxResult.error(e.getMessage()), signature, method, args, 0);
            throw e;
        }
    }

    @Async
    public void log(Log log, HttpServletRequest request, AjaxResult result, MethodSignature signature, Method method, Object[] args, long cost) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        // 保存日志
        SysLog sysLog = new SysLog();
        sysLog.setApiName(log.value()); // 接口名称
        sysLog.setUri(request.getRequestURI()); // uri
        sysLog.setHttpMethod(request.getMethod()); // 请求方式
        sysLog.setQueryParams(request.getQueryString()); // 查询参数
        // 获取方法的参数列表
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            // 判断是否为请求体
            if (parameter.isAnnotationPresent(RequestBody.class)) {
                String bodyJson = mapper.writeValueAsString(args[i]);
                sysLog.setBodyParams("null".equals(bodyJson) ? "" : bodyJson);
                break;
            }
        }
        sysLog.setResponseResult(mapper.writeValueAsString(result)); // 结果
        sysLog.setMethod(signature.getDeclaringTypeName() + "." + method.getName()); // 执行的方法
        sysLog.setRequestTime(new Date()); // 执行时间戳
        sysLog.setRequestIp(ReqUtils.getIP(request)); // 请求者ip
        sysLog.setUserId(ReqUtils.getUserId()); // 调用者id
        sysLog.setCost(cost); // 耗时
        sysLogMapper.insert(sysLog);
    }
}
